
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Text;

namespace Swaf
{

	/// <summary>
	/// Exception class that is thrown when a error occurs while reading data from a <c>StringStream</c>
	/// object.</summary>
	[Serializable]
	public class StreamReadException : BaseException
	{
		public StreamReadException(string msg)
			:base(msg)
		{}

		public StreamReadException(string msg, Exception innerException)
			:base(msg, innerException)
		{}
		public StreamReadException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) 
			: base(info, context)
		{
		}
	}

	/// <summary>
	/// Exception class that is thrown when a error occurs while writing data from a <c>StringStream</c>
	/// object.</summary>
	[Serializable]
	public class StreamWriteException : ApplicationException
	{
		public StreamWriteException(string msg)
			:base(msg)
		{}

		public StreamWriteException(string msg, Exception innerException)
			:base(msg, innerException)
	{}
	}

	/// <summary>
	/// String buffer class that can read and write numbers and text
	/// into a buffer without having to realocate for each "add" into the
	/// buffer.</summary>
	public class StringStream
	{
		public StringStream()
			:this(m_defaultStartBufferSize)
		{
		}

		public StringStream(int startBuffSize)
		{
			m_readPos = m_writePos = 0;
			m_buffer = new char[startBuffSize];
		}

		public StringStream(string initBuffer)
		{
			int size = initBuffer.Length;
			if(size < m_defaultStartBufferSize)
				size = m_defaultStartBufferSize;
			m_buffer = new char[size];
			initBuffer.CopyTo(0,m_buffer,0,initBuffer.Length);

			m_writePos = initBuffer.Length;
			m_readPos = 0;
		}

		public int readInt()
		{
			int tagPos = m_readPos;
			while(m_buffer[tagPos] != ':' && tagPos < m_writePos)
				++tagPos;
			if(m_buffer[tagPos] == ':')
			{
				int val = Int32.Parse(new String(m_buffer, m_readPos, tagPos - m_readPos));
				m_readPos = tagPos +1;
				return val;
			}
			throw new StreamReadException("Cannot find formating char for reading an int");
		}

		public void writeInt(int num)
		{
			string strNum = num.ToString();
			if(strNum.Length > m_buffer.Length)
				expandBuffer();

			strNum.CopyTo(0, m_buffer, m_writePos, strNum.Length);
			m_writePos += strNum.Length +1;
			m_buffer[m_writePos -1] = ':';
		}

		public long readLong()
		{
			int tagPos = m_readPos;
			while(m_buffer[tagPos] != ':' && tagPos < m_writePos)
				++tagPos;
			if(m_buffer[tagPos] == ':')
			{
				long val = Int64.Parse(new String(m_buffer, m_readPos, tagPos - m_readPos));
				m_readPos = tagPos +1;
				return val;
			}
			throw new StreamReadException("Cannot find formating char for reading an int");
		}

		public void writeLong(long num)
		{
			string strNum = num.ToString();
			if(strNum.Length > m_buffer.Length)
				expandBuffer();

			strNum.CopyTo(0, m_buffer, m_writePos, strNum.Length);
			m_writePos += strNum.Length +1;
			m_buffer[m_writePos -1] = ':';
		}


		public string readString()
		{
			int len = readInt();
			if(m_readPos + len >= m_writePos)
				len = m_writePos - m_readPos;// -1;
			string str = new String(m_buffer, m_readPos, len);
			m_readPos += len;
			return str;
		}

		public void writeString(string str)
		{
			int len = str.Length;
			writeInt(len);
			if(m_writePos + len > m_buffer.Length)
				expandBuffer();
			str.CopyTo(0, m_buffer, m_writePos, len);
			m_writePos += len;
		}

		public override string ToString()
		{
			return new String(m_buffer,0,m_writePos);
		}

		public bool eof 
		{get{
			 return m_readPos == m_writePos;
		}}

		private void expandBuffer()
		{
			throw new StreamWriteException("Beyond capacity of buffer");
		}

		private static int m_defaultStartBufferSize = 1024;

		private char[] m_buffer;
		private int m_readPos, m_writePos;
	}
}